rr suppressPackageStartupMessages(library(dplyr)) suppressPackageStartupMessages(library(Seurat)) suppressPackageStartupMessages(library(clustree)) suppressPackageStartupMessages(library(ggplot2)) suppressPackageStartupMessages(library(VennDiagram)) suppressPackageStartupMessages(library(cowplot)) suppressPackageStartupMessages(library(harmony))

rr path<-~/Documents/Kia/CPepi_review/results/
sample.names<-c(32) subset.name<-
source(~/Documents/scripts/preprosessing_May.2020.R) gene.markers<-read.csv(~/Documents/gene_protein_lists/markergenes_mouse.csv) cols.use=c(1,3,1,,,1,,,3,,4,,,,3,1,, , ,, 3, 30, , , , 30)

rr seur_full<-readRDS(paste0(path,sample.names,.seurat.no.doublets.rds))

rr DimPlot(seur_full,label=T, repel=T,cols=cols.use, group.by = ,reduction = 30)+ggtitle( dataset : annotation)

rr DimPlot(seur_full,label=T, repel=T,cols=cols.use, group.by = _cell_type,reduction = 30)+ggtitle(dataset : Manuscript cell types)

Subset BAMs

rr Idents(seur_full)=
clusters<-c(paste(, 1:5), prolif,1,2 ,  ) clusters[!clusters %in% Idents(seur_full)] #check if some of the cluster names is not correct

character(0)

Subset the cells

rr seur<-seur_full[,WhichCells(seur_full, idents=clusters)] seur$full.dataset.annot=Idents(seur)

Remove genes that are not expressed in any cell

rr num.cells.per.gene <- rowSums(as.matrix(GetAssayData(seur, slot = )) > 0) genes.use <- names(num.cells.per.gene[which(num.cells.per.gene >= 1)]) seur<-subset(seur,features=genes.use)

rr cat(/cells of full data : ,dim(seur_full))

genes/cells of full data : 
 12283 2155

rr cat(\ngenes/cells of subset : ,dim(seur))


genes/cells of subset : 
 12177 1486

Standard preprocessing and UMAP of the subsetted dataset (Selecting variable genes, scaling, PCA, UMAP )

rr seur <- NormalizeData(seur,verbose = F) seur <- FindVariableFeatures(seur,verbose=F) seur <- ScaleData(seur,verbose = F) seur <- RunPCA(seur, features = VariableFeatures(seur),verbose=F)

rr ElbowPlot(object = seur,ndims =50)

PC 1:10

rr dims.use=10

rr seur <- RunUMAP(seur, dims = 1:dims.use, verbose=F,reduction.name =paste0(,dims.use),reduction.key =paste0(,dims.use,_))

rr DimPlot(object = seur, group.by = _cell_type,label=T, repel=T,reduction=paste0(,dims.use))+ggtitle(paste(subset.name,: Manuscript cell types))

rr DimPlot(object = seur, group.by = .dataset.annot,label=T, repel=T,reduction=paste0(,dims.use))+ggtitle(paste(subset.name,: annotation from full dataset))

rr DimPlot(object = seur, group.by = .immgen.main,label=T, repel=T, cols=cols.use,reduction=paste0(,dims.use))+ggtitle(paste(subset.name,: singler.immgen.main))

rr FeaturePlot(seur, c(6c2,2,4a7,2,,,2ry12,7, 3e, 67, 5, 3),reduction=paste0(,dims.use))

Clustering with Leiden algorithm

rr seur <- FindNeighbors(seur, dims = 1:dims.use, verbose=F,graph.name =paste0(_snn_PC,dims.use)) for ( i in seq(0,2, 0.25)) seur <- FindClusters(seur, resolution = i, verbose=F, algorithm = 4,graph.name =paste0(_snn_PC,dims.use)) # algorithm= 4 is Leiden algorithm - often performs better

Plot of a clustering tree showing the relationship between clusterings at different resolutions. (using the clustree package)

rr clustree(seur, prefix = paste0(_snn_PC,dims.use,_res.)) + ggtitle(paste(subset.name,: Clustering tree PC=, dims.use))

rr plot<-list() for ( res in c(0.5, 0.75,1,1.25)) plot[[as.character(res)]]<-DimPlot(seur, pt.size = 1,label=T,repel=T, group.by = paste0(_snn_PC,dims.use,_res.,res),reduction=paste0(,dims.use)) + ggtitle(paste(=,dims.use,=,res)) plot_grid(plotlist=plot)

Let’s find differentially expressed genes per cluster

rr res=0.75 Idents(seur)= paste0(_snn_PC,dims.use,_res.,res)

rr res=0.75 dims.use=10 DEgenes_list <- readRDS( paste0( path,.res,res,_,,dims.use,_,subset.name,_,sample.names,.rds))

rr features.use=unlist(lapply(DEgenes_list, function(x) { head(x[x$avg_logFC>0,]$gene)})) DoHeatmap(seur, features = features.use, assay = , angle = 90, label =T, size=4) + scale_fill_gradient2(low = , mid = ,high = )+ theme(axis.text.y= element_text(size=11))+ ggtitle(paste( res=,res,  PC= , dims.use))

Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

rr DimPlot(object = seur,label=T, repel=T, reduction=paste0(,dims.use))+ggtitle(paste( res=,res,  PC= , dims.use))

rr ### Save as excel table setwd(path) first_sheet_name<-names(DEgenes_list)[1] #JAVA specific garbage collection jgc <- function() { rJava::.jcall(/lang/System, method = ) } #Create the excel file and add the first sheet write.xlsx2(DEgenes_list[[first_sheet_name]], file=paste0(.res,res,_,,dims.use,_,subset.name,_,sample.names,.xlsx), sheetName=first_sheet_name, row.names=FALSE) #Add the remaining sheets tot he excel file for ( i in names(DEgenes_list)[names(DEgenes_list)!=first_sheet_name]) { gc() jgc() message(sheet , i) write.xlsx2(DEgenes_list[[i]], file=paste0(.res,res,_,,dims.use,_,subset.name,_,sample.names,.xlsx), sheetName=i, append=TRUE, row.names=FALSE) }


PC 1:15

rr dims.use=15

rr seur <- RunUMAP(seur, dims = 1:dims.use, verbose=F,reduction.name =paste0(,dims.use),reduction.key =paste0(,dims.use,_))

rr DimPlot(object = seur, group.by = _cell_type,label=T, repel=T,reduction=paste0(,dims.use))+ggtitle(paste(subset.name,: Manuscript cell types))

rr DimPlot(object = seur, group.by = .dataset.annot,label=T, repel=T,reduction=paste0(,dims.use))+ggtitle(paste(subset.name,: annotation from full dataset))

Clustering with Leiden algorithm

rr seur <- FindNeighbors(seur, dims = 1:dims.use, verbose=F,graph.name =paste0(_snn_PC,dims.use)) for ( i in seq(0,2, 0.25)) seur <- FindClusters(seur, resolution = i, verbose=F, algorithm = 4,graph.name =paste0(_snn_PC,dims.use)) # algorithm= 4 is Leiden algorithm - often performs better

Plot of a clustering tree showing the relationship between clusterings at different resolutions. (using the clustree package)

rr clustree(seur, prefix = paste0(_snn_PC,dims.use,_res.)) + ggtitle(paste(subset.name,: Clustering tree PC=, dims.use))

rr plot<-list() for ( res in c(0.5, 0.75,1,1.25)) plot[[as.character(res)]]<-DimPlot(seur, pt.size = 1,label=T,repel=T, group.by = paste0(_snn_PC,dims.use,_res.,res),reduction=paste0(,dims.use)) + ggtitle(paste(=,dims.use,=,res)) plot_grid(plotlist=plot)

Visualize the same clusterings on UMAP with 10 PC

rr plot<-list() for ( res in c(0.5, 0.75,1,1.25)) plot[[as.character(res)]]<-DimPlot(seur,label=T,repel=T, group.by = paste0(_snn_PC,dims.use,_res.,res), reduction= paste0(10)) + ggtitle(paste(=,dims.use,=,res)) plot_grid(plotlist=plot)

Let’s find differentially expressed genes per cluster

rr res=0.75 Idents(seur)= paste0(_snn_PC,dims.use,_res.,res)

rr res=0.75 dims.use=15 DEgenes_list <- readRDS( paste0( path,.res,res,_,,dims.use,_,subset.name,_,sample.names,.rds))

rr features.use=unlist(lapply(DEgenes_list, function(x) { head(x[x$avg_logFC>0,]$gene)})) DoHeatmap(seur, features = features.use, assay = , angle = 90, label =T, size=4) + scale_fill_gradient2(low = , mid = ,high = )+ theme(axis.text.y= element_text(size=11))+ ggtitle(paste( res=,res,  PC= , dims.use))

Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

rr DimPlot(object = seur,label=T, repel=T, reduction=paste0(,dims.use))+ggtitle(paste( res=,res,  PC= , dims.use))

rr ### Save as excel table setwd(path) first_sheet_name<-names(DEgenes_list)[1] #JAVA specific garbage collection jgc <- function() { rJava::.jcall(/lang/System, method = ) } #Create the excel file and add the first sheet write.xlsx2(DEgenes_list[[first_sheet_name]], file=paste0(.res,res,_,,dims.use,_,subset.name,_,sample.names,.xlsx), sheetName=first_sheet_name, row.names=FALSE) #Add the remaining sheets tot he excel file for ( i in names(DEgenes_list)[names(DEgenes_list)!=first_sheet_name]) { gc() jgc() message(sheet , i) write.xlsx2(DEgenes_list[[i]], file=paste0(.res,res,_,,dims.use,_,subset.name,_,sample.names,.xlsx), sheetName=i, append=TRUE, row.names=FALSE) }


PC 1:20

rr dims.use=20

rr seur <- RunUMAP(seur, dims = 1:dims.use, verbose=F,reduction.name =paste0(,dims.use),reduction.key =paste0(,dims.use,_))

rr DimPlot(object = seur, group.by = _cell_type,label=T, repel=T,reduction=paste0(,dims.use))+ggtitle(paste(subset.name,: Manuscript cell types))

rr DimPlot(object = seur, group.by = .dataset.annot,label=T, repel=T,reduction=paste0(,dims.use))+ggtitle(paste(subset.name,: annotation from full dataset))

Clustering with Leiden algorithm

rr seur <- FindNeighbors(seur, dims = 1:dims.use, verbose=F,graph.name =paste0(_snn_PC,dims.use)) for ( i in seq(0,2, 0.25)) seur <- FindClusters(seur, resolution = i, verbose=F, algorithm = 4,graph.name =paste0(_snn_PC,dims.use)) # algorithm= 4 is Leiden algorithm - often performs better

Plot of a clustering tree showing the relationship between clusterings at different resolutions. (using the clustree package)

rr clustree(seur, prefix = paste0(_snn_PC,dims.use,_res.)) + ggtitle(paste(subset.name,: Clustering tree PC=, dims.use))

rr plot<-list() for ( res in c(0.5, 0.75,1,1.25)) plot[[as.character(res)]]<-DimPlot(seur, pt.size = 1,label=T,repel=T, group.by = paste0(_snn_PC,dims.use,_res.,res),reduction=paste0(,dims.use)) + ggtitle(paste(=,dims.use,=,res)) plot_grid(plotlist=plot)

Visualize the same clusterings on UMAP with 10 PC

rr plot<-list() for ( res in c(0.5, 0.75,1,1.25)) plot[[as.character(res)]]<-DimPlot(seur,label=T,repel=T, group.by = paste0(_snn_PC,dims.use,_res.,res), reduction= paste0(10)) + ggtitle(paste(=,dims.use,=,res)) plot_grid(plotlist=plot)

Let’s find differentially expressed genes per cluster

rr res=1 Idents(seur)= paste0(_snn_PC,dims.use,_res.,res)

rr res=1 dims.use=10 DEgenes_list <- readRDS( paste0( path,.res,res,_,,dims.use,_,subset.name,_,sample.names,.rds))

rr features.use=unlist(lapply(DEgenes_list, function(x) { head(x[x$avg_logFC>0,]$gene)})) DoHeatmap(seur, features = features.use, assay = , angle = 90, label =T, size=4) + scale_fill_gradient2(low = , mid = ,high = )+ theme(axis.text.y= element_text(size=10))+ ggtitle(paste( res=,res,  PC= , dims.use))

Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

rr ### Save as excel table setwd(path) first_sheet_name<-names(DEgenes_list)[1] #JAVA specific garbage collection jgc <- function() { rJava::.jcall(/lang/System, method = ) } #Create the excel file and add the first sheet write.xlsx2(DEgenes_list[[first_sheet_name]], file=paste0(.res,res,_,,dims.use,_,subset.name,_,sample.names,.xlsx), sheetName=first_sheet_name, row.names=FALSE) #Add the remaining sheets tot he excel file for ( i in names(DEgenes_list)[names(DEgenes_list)!=first_sheet_name]) { gc() jgc() message(sheet , i) write.xlsx2(DEgenes_list[[i]], file=paste0(.res,res,_,,dims.use,_,subset.name,_,sample.names,.xlsx), sheetName=i, append=TRUE, row.names=FALSE) }

rr saveRDS(seur,paste0(path,subset.name,sample.names,.seurat.rds))

rr seur<-readRDS(paste0(path,subset.name,sample.names,.seurat.rds))

rr sessionInfo()

R version 4.0.3 (2020-10-10)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.2 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /home/daliya/anaconda3/lib/libmkl_rt.so

locale:
 [1] LC_CTYPE=en_US.UTF-8          LC_NUMERIC=C                  LC_TIME=de_BE.UTF-8           LC_COLLATE=en_US.UTF-8       
 [5] LC_MONETARY=de_BE.UTF-8       LC_MESSAGES=en_US.UTF-8       LC_PAPER=de_BE.UTF-8          LC_NAME=de_BE.UTF-8          
 [9] LC_ADDRESS=de_BE.UTF-8        LC_TELEPHONE=de_BE.UTF-8      LC_MEASUREMENT=de_BE.UTF-8    LC_IDENTIFICATION=de_BE.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] enrichR_2.1    biomaRt_2.46.0 xlsx_0.6.5     harmony_1.0    Rcpp_1.0.6     shiny_1.5.0    cowplot_1.1.1  ggrepel_0.9.1  clustree_0.4.3
[10] ggraph_2.0.4   ggplot2_3.3.3  Seurat_3.2.3   dplyr_1.0.3   

loaded via a namespace (and not attached):
  [1] reticulate_1.18             R.utils_2.10.1              tidyselect_1.1.0            RSQLite_2.2.2               AnnotationDbi_1.52.0       
  [6] htmlwidgets_1.5.3           grid_4.0.3                  BiocParallel_1.24.1         Rtsne_0.15                  devtools_2.3.2             
 [11] DropletUtils_1.10.2         munsell_0.5.0               codetools_0.2-16            ica_1.0-2                   future_1.21.0              
 [16] miniUI_0.1.1.1              withr_2.4.0                 colorspace_2.0-0            Biobase_2.50.0              knitr_1.30                 
 [21] rstudioapi_0.13             stats4_4.0.3                SingleCellExperiment_1.12.0 ROCR_1.0-11                 tensor_1.5                 
 [26] rJava_0.9-13                listenv_0.8.0               MatrixGenerics_1.2.0        labeling_0.4.2              GenomeInfoDbData_1.2.4     
 [31] polyclip_1.10-0             bit64_4.0.5                 farver_2.0.3                rhdf5_2.34.0                rprojroot_2.0.2            
 [36] parallelly_1.23.0           vctrs_0.3.6                 generics_0.1.0              xfun_0.20                   BiocFileCache_1.14.0       
 [41] R6_2.5.0                    GenomeInfoDb_1.26.2         graphlayouts_0.7.1          rsvd_1.0.3                  locfit_1.5-9.4             
 [46] AnnotationFilter_1.14.0     bitops_1.0-6                rhdf5filters_1.2.0          spatstat.utils_2.1-0        DelayedArray_0.16.0        
 [51] assertthat_0.2.1            promises_1.1.1              scales_1.1.1                gtable_0.3.0                beachmat_2.6.4             
 [56] Cairo_1.5-12.2              globals_0.14.0              processx_3.4.5              goftest_1.2-2               ensembldb_2.14.0           
 [61] tidygraph_1.2.0             rlang_0.4.10                splines_4.0.3               rtracklayer_1.50.0          lazyeval_0.2.2             
 [66] checkmate_2.0.0             yaml_2.2.1                  reshape2_1.4.4              abind_1.4-5                 backports_1.2.1            
 [71] GenomicFeatures_1.42.1      httpuv_1.5.5                usethis_2.0.0               tools_4.0.3                 ellipsis_0.3.1             
 [76] RColorBrewer_1.1-2          BiocGenerics_0.36.0         sessioninfo_1.1.1           ggridges_0.5.3              plyr_1.8.6                 
 [81] sparseMatrixStats_1.2.0     progress_1.2.2              zlibbioc_1.36.0             purrr_0.3.4                 RCurl_1.98-1.2             
 [86] ps_1.5.0                    prettyunits_1.1.1           rpart_4.1-15                openssl_1.4.3               deldir_0.2-9               
 [91] pbapply_1.4-3               viridis_0.5.1               S4Vectors_0.28.1            zoo_1.8-8                   SummarizedExperiment_1.20.0
 [96] cluster_2.1.0               fs_1.5.0                    magrittr_2.0.1              data.table_1.13.6           RSpectra_0.16-0            
[101] scattermore_0.7             lmtest_0.9-38               RANN_2.6.1                  ProtGenerics_1.22.0         fitdistrplus_1.1-3         
[106] matrixStats_0.58.0          pkgload_1.1.0               hms_1.0.0                   xlsxjars_0.6.1              patchwork_1.1.1            
[111] mime_0.9                    evaluate_0.14               xtable_1.8-4                XML_3.99-0.5                readxl_1.3.1               
[116] IRanges_2.24.1              gridExtra_2.3               testthat_3.0.1              compiler_4.0.3              tibble_3.0.5               
[121] KernSmooth_2.23-17          crayon_1.4.0                R.oo_1.24.0                 htmltools_0.5.1             mgcv_1.8-33                
[126] later_1.1.0.1               tidyr_1.1.2                 DBI_1.1.1                   tweenr_1.0.1                dbplyr_2.0.0               
[131] MASS_7.3-53                 rappdirs_0.3.1              Matrix_1.3-2                cli_2.2.0                   R.methodsS3_1.8.1          
[136] parallel_4.0.3              igraph_1.2.6                GenomicRanges_1.42.0        pkgconfig_2.0.3             GenomicAlignments_1.26.0   
[141] scuttle_1.0.4               plotly_4.9.3                xml2_1.3.2                  dqrng_0.2.1                 XVector_0.30.0             
[146] callr_3.5.1                 stringr_1.4.0               digest_0.6.27               sctransform_0.3.2           RcppAnnoy_0.0.18           
[151] Biostrings_2.58.0           spatstat.data_2.1-0         rmarkdown_2.6               cellranger_1.1.0            leiden_0.3.6               
[156] uwot_0.1.10                 edgeR_3.32.1                DelayedMatrixStats_1.12.2   curl_4.3                    Rsamtools_2.6.0            
[161] rjson_0.2.20                lifecycle_0.2.0             nlme_3.1-149                jsonlite_1.7.2              Rhdf5lib_1.12.0            
[166] desc_1.2.0                  fansi_0.4.2                 viridisLite_0.3.0           askpass_1.1                 limma_3.46.0               
[171] pillar_1.4.7                lattice_0.20-41             pkgbuild_1.2.0              fastmap_1.0.1               httr_1.4.2                 
[176] survival_3.2-7              remotes_2.2.0               glue_1.4.2                  spatstat_1.64-1             png_0.1-7                  
[181] bit_4.0.4                   ggforce_0.3.2               stringi_1.5.3               HDF5Array_1.18.0            blob_1.2.1                 
[186] memoise_1.1.0               irlba_2.3.3                 future.apply_1.7.0         
LS0tCnRpdGxlOiAiSlAzMiAoQWN0RCBDUCBtb3VzZSk6IEJBTSByZWNsdXN0ZXJpbmciCm91dHB1dDogaHRtbF9ub3RlYm9vawpkYXRlOiAnQ3JlYXRlZCBvbjogYHIgZm9ybWF0KFN5cy5EYXRlKCksICIlQiAlZCwgJVkiKWAnCi0tLQogIAoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGRwbHlyKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoU2V1cmF0KSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoY2x1c3RyZWUpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShnZ3Bsb3QyKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoVmVubkRpYWdyYW0pKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShjb3dwbG90KSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoaGFybW9ueSkpCmBgYAoKCmBgYHtyfQpwYXRoPC0iL3BhdGgvdG8vd29ya2luZ19kaXIiCnNhbXBsZS5uYW1lczwtYygiSlAzMiIpCnN1YnNldC5uYW1lPC0iQkFNIgpzb3VyY2UoIn4vRG9jdW1lbnRzL3NjcmlwdHMvcHJlcHJvc2Vzc2luZ19NYXkuMjAyMC5SIikKZ2VuZS5tYXJrZXJzPC1yZWFkLmNzdigifi9Eb2N1bWVudHMvZ2VuZV9wcm90ZWluX2xpc3RzL21hcmtlcmdlbmVzX21vdXNlLmNzdiIpCmNvbHMudXNlPWMoImJyb3duMSIsImdvbGRlbnJvZDMiLCJnb2xkZW5yb2QxIiwiZGFya29yY2hpZCIsIm1lZGl1bXB1cnBsZSIsImRhcmtvbGl2ZWdyZWVuMSIsIm1hZ2VudGEiLCJkb2RnZXJibHVlIiwidHVycXVvaXNlMyIsImxpZ2h0Ymx1ZSIsImdvbGQ0IiwiY29yYWwiLCJ2aW9sZXRyZWQiLCJncmV5IiwiZ3JlZW4zIiwiZ29sZGVucm9kMSIsInBhbGV2aW9sZXRyZWQiLCAic2VhZ3JlZW4iLCAicmVkIiwieWVsbG93IiwgImJyb3duMyIsICJncmV5MzAiLCAicGluayIsICJiaXNxdWUiLCAieWVsbG93Z3JlZW4iLCAiZ3JleTMwIikKYGBgCgpgYGB7cn0Kc2V1cl9mdWxsPC1yZWFkUkRTKHBhc3RlMChwYXRoLHNhbXBsZS5uYW1lcywiLnNldXJhdC5uby5kb3VibGV0cy5yZHMiKSkKYGBgCgoKYGBge3IgLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTAsd2FybmluZz1GQUxTRX0KRGltUGxvdChzZXVyX2Z1bGwsbGFiZWw9VCwgcmVwZWw9VCxjb2xzPWNvbHMudXNlLCBncm91cC5ieSA9ICJhbm5vdCIscmVkdWN0aW9uID0gInVtYXBQQzMwIikrZ2d0aXRsZSggIkZ1bGwgZGF0YXNldCAgOiBhbm5vdGF0aW9uIikKYGBgCmBgYHtyICwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDEwLHdhcm5pbmc9RkFMU0V9CkRpbVBsb3Qoc2V1cl9mdWxsLGxhYmVsPVQsIHJlcGVsPVQsY29scz1jb2xzLnVzZSwgZ3JvdXAuYnkgPSAiTWFudXNjcmlwdF9jZWxsX3R5cGUiLHJlZHVjdGlvbiA9ICJ1bWFwUEMzMCIpK2dndGl0bGUoIkZ1bGwgZGF0YXNldCAgOiBNYW51c2NyaXB0IGNlbGwgdHlwZXMiKQpgYGAKCiMjIyMgU3Vic2V0IEJBTXMKYGBge3Isd2FybmluZz1GQUxTRX0KSWRlbnRzKHNldXJfZnVsbCk9ImFubm90IgpjbHVzdGVyczwtYyhwYXN0ZSgiQkFNIiwgMTo1KSwgIkJBTSBwcm9saWYiLCJDUGVwaSAxIiwiQ1BlcGkgMiIgLCAiTW9ubyIgKQpjbHVzdGVyc1shY2x1c3RlcnMgJWluJSBJZGVudHMoc2V1cl9mdWxsKV0gI2NoZWNrIGlmIHNvbWUgb2YgdGhlIGNsdXN0ZXIgbmFtZXMgaXMgbm90IGNvcnJlY3QKYGBgClN1YnNldCB0aGUgY2VsbHMKYGBge3Isd2FybmluZz1GQUxTRX0Kc2V1cjwtc2V1cl9mdWxsWyxXaGljaENlbGxzKHNldXJfZnVsbCwgaWRlbnRzPWNsdXN0ZXJzKV0Kc2V1ciRmdWxsLmRhdGFzZXQuYW5ub3Q9SWRlbnRzKHNldXIpCmBgYAoKClJlbW92ZSBnZW5lcyB0aGF0IGFyZSBub3QgZXhwcmVzc2VkIGluIGFueSBjZWxsCmBgYHtyLHdhcm5pbmc9RkFMU0V9Cm51bS5jZWxscy5wZXIuZ2VuZSA8LSByb3dTdW1zKGFzLm1hdHJpeChHZXRBc3NheURhdGEoc2V1ciwgc2xvdCA9ICJjb3VudHMiKSkgPiAwKQogIGdlbmVzLnVzZSA8LSBuYW1lcyhudW0uY2VsbHMucGVyLmdlbmVbd2hpY2gobnVtLmNlbGxzLnBlci5nZW5lID49IDEpXSkKICBzZXVyPC1zdWJzZXQoc2V1cixmZWF0dXJlcz1nZW5lcy51c2UpCmBgYApgYGB7cix3YXJuaW5nPUZBTFNFfQpjYXQoImdlbmVzL2NlbGxzIG9mIGZ1bGwgZGF0YSA6IFxuIixkaW0oc2V1cl9mdWxsKSkKY2F0KCJcbmdlbmVzL2NlbGxzIG9mIHN1YnNldCA6IFxuIixkaW0oc2V1cikpCmBgYAoKIyMjIyBTdGFuZGFyZCBwcmVwcm9jZXNzaW5nIGFuZCBVTUFQIG9mIHRoZSBzdWJzZXR0ZWQgZGF0YXNldCAoU2VsZWN0aW5nIHZhcmlhYmxlIGdlbmVzLCBzY2FsaW5nLCBQQ0EsIFVNQVAgKQpgYGB7cix3YXJuaW5nPUZBTFNFfQpzZXVyIDwtIE5vcm1hbGl6ZURhdGEoc2V1cix2ZXJib3NlID0gRikKc2V1ciA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhzZXVyLHZlcmJvc2U9RikKc2V1ciA8LSBTY2FsZURhdGEoc2V1cix2ZXJib3NlID0gRikKc2V1ciA8LSBSdW5QQ0Eoc2V1ciwgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKHNldXIpLHZlcmJvc2U9RikKYGBgCmBgYHtyICwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDEwLHdhcm5pbmc9RkFMU0V9CkVsYm93UGxvdChvYmplY3QgPSBzZXVyLG5kaW1zID01MCkKYGBgCgoKCiMjIyBQQyAxOjEwCmBgYHtyLHdhcm5pbmc9RkFMU0V9CmRpbXMudXNlPTEwCmBgYApgYGB7cix3YXJuaW5nPUZBTFNFfQpzZXVyIDwtIFJ1blVNQVAoc2V1ciwgZGltcyA9IDE6ZGltcy51c2UsIHZlcmJvc2U9RixyZWR1Y3Rpb24ubmFtZSA9cGFzdGUwKCJ1bWFwUEMiLGRpbXMudXNlKSxyZWR1Y3Rpb24ua2V5ID1wYXN0ZTAoInVtYXBQQyIsZGltcy51c2UsIl8iKSkKYGBgCmBgYHtyICwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDcsd2FybmluZz1GQUxTRX0KRGltUGxvdChvYmplY3QgPSBzZXVyLCBncm91cC5ieSA9ICJNYW51c2NyaXB0X2NlbGxfdHlwZSIsbGFiZWw9VCwgcmVwZWw9VCxyZWR1Y3Rpb249cGFzdGUwKCJ1bWFwUEMiLGRpbXMudXNlKSkrZ2d0aXRsZShwYXN0ZShzdWJzZXQubmFtZSwiOiBNYW51c2NyaXB0IGNlbGwgdHlwZXMiKSkKYGBgCmBgYHtyICwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDcsd2FybmluZz1GQUxTRX0KRGltUGxvdChvYmplY3QgPSBzZXVyLCBncm91cC5ieSA9ICJmdWxsLmRhdGFzZXQuYW5ub3QiLGxhYmVsPVQsIHJlcGVsPVQscmVkdWN0aW9uPXBhc3RlMCgidW1hcFBDIixkaW1zLnVzZSkpK2dndGl0bGUocGFzdGUoc3Vic2V0Lm5hbWUsIjogYW5ub3RhdGlvbiBmcm9tIGZ1bGwgZGF0YXNldCIpKQpgYGAKYGBge3IgLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gNyx3YXJuaW5nPUZBTFNFfQpEaW1QbG90KG9iamVjdCA9IHNldXIsIGdyb3VwLmJ5ID0gInNpbmdsZXIuaW1tZ2VuLm1haW4iLGxhYmVsPVQsIHJlcGVsPVQsIGNvbHM9Y29scy51c2UscmVkdWN0aW9uPXBhc3RlMCgidW1hcFBDIixkaW1zLnVzZSkpK2dndGl0bGUocGFzdGUoc3Vic2V0Lm5hbWUsIjogc2luZ2xlci5pbW1nZW4ubWFpbiIpKQpgYGAKCmBgYHtyICwgZmlnLmhlaWdodCA9OCwgZmlnLndpZHRoID0xMix3YXJuaW5nPUZBTFNFfQpGZWF0dXJlUGxvdChzZXVyLCBjKCJMeTZjMiIsIkNjcjIiLCJNczRhNyIsIkVhcjIiLCJBY2UiLCJTcGFyYyIsIlAycnkxMiIsIkNzdDciLCAiQ2QzZSIsICJNa2k2NyIsICJNY201IiwgIk1jbTMiKSxyZWR1Y3Rpb249cGFzdGUwKCJ1bWFwUEMiLGRpbXMudXNlKSkgCmBgYAoKCgojIyMjIENsdXN0ZXJpbmcgd2l0aCBMZWlkZW4gYWxnb3JpdGhtCgpgYGB7ciAsd2FybmluZz1GQUxTRX0Kc2V1ciA8LSBGaW5kTmVpZ2hib3JzKHNldXIsIGRpbXMgPSAxOmRpbXMudXNlLCB2ZXJib3NlPUYsZ3JhcGgubmFtZSA9cGFzdGUwKCJSTkFfc25uX1BDIixkaW1zLnVzZSkpCmZvciAoIGkgaW4gc2VxKDAsMiwgMC4yNSkpCnNldXIgPC0gRmluZENsdXN0ZXJzKHNldXIsIHJlc29sdXRpb24gPSBpLCB2ZXJib3NlPUYsIGFsZ29yaXRobSA9IDQsZ3JhcGgubmFtZSA9cGFzdGUwKCJSTkFfc25uX1BDIixkaW1zLnVzZSkpCiMgYWxnb3JpdGhtPSA0IGlzIExlaWRlbiBhbGdvcml0aG0gLSBvZnRlbiBwZXJmb3JtcyBiZXR0ZXIKYGBgCgpQbG90IG9mIGEgY2x1c3RlcmluZyB0cmVlIHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNsdXN0ZXJpbmdzIGF0IGRpZmZlcmVudCByZXNvbHV0aW9ucy4gKHVzaW5nIHRoZSBjbHVzdHJlZSBwYWNrYWdlKQpgYGB7ciAsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4LHdhcm5pbmc9RkFMU0V9CmNsdXN0cmVlKHNldXIsIHByZWZpeCA9IHBhc3RlMCgiUk5BX3Nubl9QQyIsZGltcy51c2UsIl9yZXMuIikpICsKIGdndGl0bGUocGFzdGUoc3Vic2V0Lm5hbWUsIjogQ2x1c3RlcmluZyB0cmVlIFBDPSIsIGRpbXMudXNlKSkKYGBgCgpgYGB7ciAsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPTEwLHdhcm5pbmc9RkFMU0V9CnBsb3Q8LWxpc3QoKQpmb3IgKCByZXMgaW4gYygwLjUsIDAuNzUsMSwxLjI1KSkKcGxvdFtbYXMuY2hhcmFjdGVyKHJlcyldXTwtRGltUGxvdChzZXVyLCBwdC5zaXplID0gMSxsYWJlbD1ULHJlcGVsPVQsIGdyb3VwLmJ5ID0gcGFzdGUwKCJSTkFfc25uX1BDIixkaW1zLnVzZSwiX3Jlcy4iLHJlcykscmVkdWN0aW9uPXBhc3RlMCgidW1hcFBDIixkaW1zLnVzZSkpICsKICAgZ2d0aXRsZShwYXN0ZSgiUEMgPSIsZGltcy51c2UsInJlcz0iLHJlcykpCnBsb3RfZ3JpZChwbG90bGlzdD1wbG90KQpgYGAKIyMjIExldCdzIGZpbmQgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIHBlciBjbHVzdGVyCgpgYGB7cix3YXJuaW5nPUZBTFNFfQpyZXM9MC43NQpJZGVudHMoc2V1cik9ICBwYXN0ZTAoIlJOQV9zbm5fUEMiLGRpbXMudXNlLCJfcmVzLiIscmVzKQpgYGAKYGBge3Isd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0KREVnZW5lc19saXN0PC1saXN0KCkKZm9yICggaSBpbiBsZXZlbHMoSWRlbnRzKHNldXIpKSl7CkRFZ2VuZXNfbGlzdFtbaV1dPC0gIGZpbmQubWFya2Vycy5kZXRhaWxlZChzZXVyLGlkZW50LjEudXNlPWksIGRhdGFzZXQubmFtZT1wYXN0ZShzYW1wbGUubmFtZXMsIHN1YnNldC5uYW1lKSxtaW4uY2VsbHMuZ3JvdXAudXNlPTIsIHBzZXVkb2NvdW50ID0gMC4xKQp9CnNhdmVSRFMoREVnZW5lc19saXN0LCBwYXN0ZTAoIHBhdGgsIkRFZ2VuZXMucmVzIixyZXMsIl8iLCJQQyIsZGltcy51c2UsIl8iLHN1YnNldC5uYW1lLCJfIixzYW1wbGUubmFtZXMsIi5yZHMiKSkKYGBgCgpgYGB7cix3YXJuaW5nPUZBTFNFfQpyZXM9MC43NQpkaW1zLnVzZT0xMApERWdlbmVzX2xpc3QgPC0gcmVhZFJEUyggcGFzdGUwKCBwYXRoLCJERWdlbmVzLnJlcyIscmVzLCJfIiwiUEMiLGRpbXMudXNlLCJfIixzdWJzZXQubmFtZSwiXyIsc2FtcGxlLm5hbWVzLCIucmRzIikpCmBgYAoKYGBge3IgLCBmaWcuaGVpZ2h0ID02LCBmaWcud2lkdGggPTEwLHdhcm5pbmc9RkFMU0V9CmZlYXR1cmVzLnVzZT11bmxpc3QobGFwcGx5KERFZ2VuZXNfbGlzdCwgZnVuY3Rpb24oeCkgeyBoZWFkKHhbeCRhdmdfbG9nRkM+MCxdJGdlbmUpfSkpCkRvSGVhdG1hcChzZXVyLCBmZWF0dXJlcyA9IGZlYXR1cmVzLnVzZSwgYXNzYXkgPSAiUk5BIiwgYW5nbGUgPSA5MCwgbGFiZWwgPVQsIHNpemU9NCkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIixoaWdoID0gInJlZCIpKwogIHRoZW1lKGF4aXMudGV4dC55PSBlbGVtZW50X3RleHQoc2l6ZT0xMSkpKwogIGdndGl0bGUocGFzdGUoIiByZXM9IixyZXMsICIgUEM9ICIsIGRpbXMudXNlKSkKYGBgCgoKYGBge3IgLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gNSx3YXJuaW5nPUZBTFNFfQpEaW1QbG90KG9iamVjdCA9IHNldXIsbGFiZWw9VCwgcmVwZWw9VCwgcmVkdWN0aW9uPXBhc3RlMCgidW1hcFBDIixkaW1zLnVzZSkpK2dndGl0bGUocGFzdGUoIiByZXM9IixyZXMsICIgUEM9ICIsIGRpbXMudXNlKSkKYGBgCgpgYGB7cix3YXJuaW5nPUZBTFNFfQojIyMgU2F2ZSBhcyBleGNlbCB0YWJsZQpzZXR3ZChwYXRoKQpmaXJzdF9zaGVldF9uYW1lPC1uYW1lcyhERWdlbmVzX2xpc3QpWzFdCiNKQVZBIHNwZWNpZmljIGdhcmJhZ2UgY29sbGVjdGlvbiAKamdjIDwtIGZ1bmN0aW9uKCkgewogIHJKYXZhOjouamNhbGwoImphdmEvbGFuZy9TeXN0ZW0iLCBtZXRob2QgPSAiZ2MiKQogfSAKI0NyZWF0ZSB0aGUgZXhjZWwgZmlsZSBhbmQgYWRkIHRoZSBmaXJzdCBzaGVldAp3cml0ZS54bHN4MihERWdlbmVzX2xpc3RbW2ZpcnN0X3NoZWV0X25hbWVdXSwgZmlsZT1wYXN0ZTAoIkRFZ2VuZXMucmVzIixyZXMsIl8iLCJQQyIsZGltcy51c2UsIl8iLHN1YnNldC5uYW1lLCJfIixzYW1wbGUubmFtZXMsIi54bHN4IiksIHNoZWV0TmFtZT1maXJzdF9zaGVldF9uYW1lLCByb3cubmFtZXM9RkFMU0UpCiNBZGQgdGhlIHJlbWFpbmluZyBzaGVldHMgdG90IGhlIGV4Y2VsIGZpbGUKZm9yICggaSBpbiBuYW1lcyhERWdlbmVzX2xpc3QpW25hbWVzKERFZ2VuZXNfbGlzdCkhPWZpcnN0X3NoZWV0X25hbWVdKSB7CiAgZ2MoKQogIGpnYygpCiAgbWVzc2FnZSgiQWRkaW5nIHNoZWV0ICIsIGkpCiAgd3JpdGUueGxzeDIoREVnZW5lc19saXN0W1tpXV0sIGZpbGU9cGFzdGUwKCJERWdlbmVzLnJlcyIscmVzLCJfIiwiUEMiLGRpbXMudXNlLCJfIixzdWJzZXQubmFtZSwiXyIsc2FtcGxlLm5hbWVzLCIueGxzeCIpLCBzaGVldE5hbWU9aSwgYXBwZW5kPVRSVUUsIHJvdy5uYW1lcz1GQUxTRSkKfQpgYGAKCgotLS0KCgojIyMgUEMgMToxNQpgYGB7cix3YXJuaW5nPUZBTFNFfQpkaW1zLnVzZT0xNQpgYGAKYGBge3Isd2FybmluZz1GQUxTRX0Kc2V1ciA8LSBSdW5VTUFQKHNldXIsIGRpbXMgPSAxOmRpbXMudXNlLCB2ZXJib3NlPUYscmVkdWN0aW9uLm5hbWUgPXBhc3RlMCgidW1hcFBDIixkaW1zLnVzZSkscmVkdWN0aW9uLmtleSA9cGFzdGUwKCJ1bWFwUEMiLGRpbXMudXNlLCJfIikpCmBgYApgYGB7ciAsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA3LHdhcm5pbmc9RkFMU0V9CkRpbVBsb3Qob2JqZWN0ID0gc2V1ciwgZ3JvdXAuYnkgPSAiTWFudXNjcmlwdF9jZWxsX3R5cGUiLGxhYmVsPVQsIHJlcGVsPVQscmVkdWN0aW9uPXBhc3RlMCgidW1hcFBDIixkaW1zLnVzZSkpK2dndGl0bGUocGFzdGUoc3Vic2V0Lm5hbWUsIjogTWFudXNjcmlwdCBjZWxsIHR5cGVzIikpCmBgYApgYGB7ciAsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA3LHdhcm5pbmc9RkFMU0V9CkRpbVBsb3Qob2JqZWN0ID0gc2V1ciwgZ3JvdXAuYnkgPSAiZnVsbC5kYXRhc2V0LmFubm90IixsYWJlbD1ULCByZXBlbD1ULHJlZHVjdGlvbj1wYXN0ZTAoInVtYXBQQyIsZGltcy51c2UpKStnZ3RpdGxlKHBhc3RlKHN1YnNldC5uYW1lLCI6IGFubm90YXRpb24gZnJvbSBmdWxsIGRhdGFzZXQiKSkKYGBgCgoKIyMjIyBDbHVzdGVyaW5nIHdpdGggTGVpZGVuIGFsZ29yaXRobQoKYGBge3IgLHdhcm5pbmc9RkFMU0V9CnNldXIgPC0gRmluZE5laWdoYm9ycyhzZXVyLCBkaW1zID0gMTpkaW1zLnVzZSwgdmVyYm9zZT1GLGdyYXBoLm5hbWUgPXBhc3RlMCgiUk5BX3Nubl9QQyIsZGltcy51c2UpKQpmb3IgKCBpIGluIHNlcSgwLDIsIDAuMjUpKQpzZXVyIDwtIEZpbmRDbHVzdGVycyhzZXVyLCByZXNvbHV0aW9uID0gaSwgdmVyYm9zZT1GLCBhbGdvcml0aG0gPSA0LGdyYXBoLm5hbWUgPXBhc3RlMCgiUk5BX3Nubl9QQyIsZGltcy51c2UpKQojIGFsZ29yaXRobT0gNCBpcyBMZWlkZW4gYWxnb3JpdGhtIC0gb2Z0ZW4gcGVyZm9ybXMgYmV0dGVyCmBgYAoKUGxvdCBvZiBhIGNsdXN0ZXJpbmcgdHJlZSBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjbHVzdGVyaW5ncyBhdCBkaWZmZXJlbnQgcmVzb2x1dGlvbnMuICh1c2luZyB0aGUgY2x1c3RyZWUgcGFja2FnZSkKYGBge3IgLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOCx3YXJuaW5nPUZBTFNFfQpjbHVzdHJlZShzZXVyLCBwcmVmaXggPSBwYXN0ZTAoIlJOQV9zbm5fUEMiLGRpbXMudXNlLCJfcmVzLiIpKSArCiBnZ3RpdGxlKHBhc3RlKHN1YnNldC5uYW1lLCI6IENsdXN0ZXJpbmcgdHJlZSBQQz0iLCBkaW1zLnVzZSkpCmBgYAoKYGBge3IgLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0xMCx3YXJuaW5nPUZBTFNFfQpwbG90PC1saXN0KCkKZm9yICggcmVzIGluIGMoMC41LCAwLjc1LDEsMS4yNSkpCnBsb3RbW2FzLmNoYXJhY3RlcihyZXMpXV08LURpbVBsb3Qoc2V1ciwgcHQuc2l6ZSA9IDEsbGFiZWw9VCxyZXBlbD1ULCBncm91cC5ieSA9IHBhc3RlMCgiUk5BX3Nubl9QQyIsZGltcy51c2UsIl9yZXMuIixyZXMpLHJlZHVjdGlvbj1wYXN0ZTAoInVtYXBQQyIsZGltcy51c2UpKSArCiAgICAgZ2d0aXRsZShwYXN0ZSgiUEMgPSIsZGltcy51c2UsInJlcz0iLHJlcykpCnBsb3RfZ3JpZChwbG90bGlzdD1wbG90KQpgYGAKCgpWaXN1YWxpemUgdGhlIHNhbWUgY2x1c3RlcmluZ3Mgb24gVU1BUCB3aXRoIDEwIFBDCmBgYHtyICwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9MTAsd2FybmluZz1GQUxTRX0KcGxvdDwtbGlzdCgpCmZvciAoIHJlcyBpbiBjKDAuNSwgMC43NSwxLDEuMjUpKQpwbG90W1thcy5jaGFyYWN0ZXIocmVzKV1dPC1EaW1QbG90KHNldXIsbGFiZWw9VCxyZXBlbD1ULCBncm91cC5ieSA9IHBhc3RlMCgiUk5BX3Nubl9QQyIsZGltcy51c2UsIl9yZXMuIixyZXMpLCAgcmVkdWN0aW9uPSAgcGFzdGUwKCJ1bWFwUEMxMCIpKSArCiAgIGdndGl0bGUocGFzdGUoIlBDID0iLGRpbXMudXNlLCJyZXM9IixyZXMpKQpwbG90X2dyaWQocGxvdGxpc3Q9cGxvdCkKYGBgCgojIyMgTGV0J3MgZmluZCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgcGVyIGNsdXN0ZXIKCmBgYHtyLHdhcm5pbmc9RkFMU0V9CnJlcz0wLjc1CklkZW50cyhzZXVyKT0gIHBhc3RlMCgiUk5BX3Nubl9QQyIsZGltcy51c2UsIl9yZXMuIixyZXMpCmBgYApgYGB7cix3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQpERWdlbmVzX2xpc3Q8LWxpc3QoKQpmb3IgKCBpIGluIGxldmVscyhJZGVudHMoc2V1cikpKXsKREVnZW5lc19saXN0W1tpXV08LSAgZmluZC5tYXJrZXJzLmRldGFpbGVkKHNldXIsaWRlbnQuMS51c2U9aSwgZGF0YXNldC5uYW1lPXBhc3RlKHNhbXBsZS5uYW1lcywgc3Vic2V0Lm5hbWUpLG1pbi5jZWxscy5ncm91cC51c2U9MiwgcHNldWRvY291bnQgPSAwLjEpCn0Kc2F2ZVJEUyhERWdlbmVzX2xpc3QsIHBhc3RlMCggcGF0aCwiREVnZW5lcy5yZXMiLHJlcywiXyIsIlBDIixkaW1zLnVzZSwiXyIsc3Vic2V0Lm5hbWUsIl8iLHNhbXBsZS5uYW1lcywiLnJkcyIpKQpgYGAKCmBgYHtyLHdhcm5pbmc9RkFMU0V9CnJlcz0wLjc1CmRpbXMudXNlPTE1CkRFZ2VuZXNfbGlzdCA8LSByZWFkUkRTKCBwYXN0ZTAoIHBhdGgsIkRFZ2VuZXMucmVzIixyZXMsIl8iLCJQQyIsZGltcy51c2UsIl8iLHN1YnNldC5uYW1lLCJfIixzYW1wbGUubmFtZXMsIi5yZHMiKSkKYGBgCgoKYGBge3IgLCBmaWcuaGVpZ2h0ID02LCBmaWcud2lkdGggPTEwLHdhcm5pbmc9RkFMU0V9CmZlYXR1cmVzLnVzZT11bmxpc3QobGFwcGx5KERFZ2VuZXNfbGlzdCwgZnVuY3Rpb24oeCkgeyBoZWFkKHhbeCRhdmdfbG9nRkM+MCxdJGdlbmUpfSkpCkRvSGVhdG1hcChzZXVyLCBmZWF0dXJlcyA9IGZlYXR1cmVzLnVzZSwgYXNzYXkgPSAiUk5BIiwgYW5nbGUgPSA5MCwgbGFiZWwgPVQsIHNpemU9NCkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIixoaWdoID0gInJlZCIpKwogIHRoZW1lKGF4aXMudGV4dC55PSBlbGVtZW50X3RleHQoc2l6ZT0xMSkpKwogIGdndGl0bGUocGFzdGUoIiByZXM9IixyZXMsICIgUEM9ICIsIGRpbXMudXNlKSkKYGBgCgpgYGB7ciAsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA1LHdhcm5pbmc9RkFMU0V9CkRpbVBsb3Qob2JqZWN0ID0gc2V1cixsYWJlbD1ULCByZXBlbD1ULCByZWR1Y3Rpb249cGFzdGUwKCJ1bWFwUEMiLGRpbXMudXNlKSkrZ2d0aXRsZShwYXN0ZSgiIHJlcz0iLHJlcywgIiBQQz0gIiwgZGltcy51c2UpKQpgYGAKYGBge3Isd2FybmluZz1GQUxTRX0KIyMjIFNhdmUgYXMgZXhjZWwgdGFibGUKc2V0d2QocGF0aCkKZmlyc3Rfc2hlZXRfbmFtZTwtbmFtZXMoREVnZW5lc19saXN0KVsxXQojSkFWQSBzcGVjaWZpYyBnYXJiYWdlIGNvbGxlY3Rpb24gCmpnYyA8LSBmdW5jdGlvbigpIHsKICBySmF2YTo6LmpjYWxsKCJqYXZhL2xhbmcvU3lzdGVtIiwgbWV0aG9kID0gImdjIikKIH0gCiNDcmVhdGUgdGhlIGV4Y2VsIGZpbGUgYW5kIGFkZCB0aGUgZmlyc3Qgc2hlZXQKd3JpdGUueGxzeDIoREVnZW5lc19saXN0W1tmaXJzdF9zaGVldF9uYW1lXV0sIGZpbGU9cGFzdGUwKCJERWdlbmVzLnJlcyIscmVzLCJfIiwiUEMiLGRpbXMudXNlLCJfIixzdWJzZXQubmFtZSwiXyIsc2FtcGxlLm5hbWVzLCIueGxzeCIpLCBzaGVldE5hbWU9Zmlyc3Rfc2hlZXRfbmFtZSwgcm93Lm5hbWVzPUZBTFNFKQojQWRkIHRoZSByZW1haW5pbmcgc2hlZXRzIHRvdCBoZSBleGNlbCBmaWxlCmZvciAoIGkgaW4gbmFtZXMoREVnZW5lc19saXN0KVtuYW1lcyhERWdlbmVzX2xpc3QpIT1maXJzdF9zaGVldF9uYW1lXSkgewogIGdjKCkKICBqZ2MoKQogIG1lc3NhZ2UoIkFkZGluZyBzaGVldCAiLCBpKQogIHdyaXRlLnhsc3gyKERFZ2VuZXNfbGlzdFtbaV1dLCBmaWxlPXBhc3RlMCgiREVnZW5lcy5yZXMiLHJlcywiXyIsIlBDIixkaW1zLnVzZSwiXyIsc3Vic2V0Lm5hbWUsIl8iLHNhbXBsZS5uYW1lcywiLnhsc3giKSwgc2hlZXROYW1lPWksIGFwcGVuZD1UUlVFLCByb3cubmFtZXM9RkFMU0UpCn0KYGBgCgotLS0KCiMjIyBQQyAxOjIwCmBgYHtyLHdhcm5pbmc9RkFMU0V9CmRpbXMudXNlPTIwCmBgYApgYGB7cix3YXJuaW5nPUZBTFNFfQpzZXVyIDwtIFJ1blVNQVAoc2V1ciwgZGltcyA9IDE6ZGltcy51c2UsIHZlcmJvc2U9RixyZWR1Y3Rpb24ubmFtZSA9cGFzdGUwKCJ1bWFwUEMiLGRpbXMudXNlKSxyZWR1Y3Rpb24ua2V5ID1wYXN0ZTAoInVtYXBQQyIsZGltcy51c2UsIl8iKSkKYGBgCmBgYHtyICwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDcsd2FybmluZz1GQUxTRX0KRGltUGxvdChvYmplY3QgPSBzZXVyLCBncm91cC5ieSA9ICJNYW51c2NyaXB0X2NlbGxfdHlwZSIsbGFiZWw9VCwgcmVwZWw9VCxyZWR1Y3Rpb249cGFzdGUwKCJ1bWFwUEMiLGRpbXMudXNlKSkrZ2d0aXRsZShwYXN0ZShzdWJzZXQubmFtZSwiOiBNYW51c2NyaXB0IGNlbGwgdHlwZXMiKSkKYGBgCmBgYHtyICwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDcsd2FybmluZz1GQUxTRX0KRGltUGxvdChvYmplY3QgPSBzZXVyLCBncm91cC5ieSA9ICJmdWxsLmRhdGFzZXQuYW5ub3QiLGxhYmVsPVQsIHJlcGVsPVQscmVkdWN0aW9uPXBhc3RlMCgidW1hcFBDIixkaW1zLnVzZSkpK2dndGl0bGUocGFzdGUoc3Vic2V0Lm5hbWUsIjogYW5ub3RhdGlvbiBmcm9tIGZ1bGwgZGF0YXNldCIpKQpgYGAKCgojIyMjIENsdXN0ZXJpbmcgd2l0aCBMZWlkZW4gYWxnb3JpdGhtCgpgYGB7ciAsd2FybmluZz1GQUxTRX0Kc2V1ciA8LSBGaW5kTmVpZ2hib3JzKHNldXIsIGRpbXMgPSAxOmRpbXMudXNlLCB2ZXJib3NlPUYsZ3JhcGgubmFtZSA9cGFzdGUwKCJSTkFfc25uX1BDIixkaW1zLnVzZSkpCmZvciAoIGkgaW4gc2VxKDAsMiwgMC4yNSkpCnNldXIgPC0gRmluZENsdXN0ZXJzKHNldXIsIHJlc29sdXRpb24gPSBpLCB2ZXJib3NlPUYsIGFsZ29yaXRobSA9IDQsZ3JhcGgubmFtZSA9cGFzdGUwKCJSTkFfc25uX1BDIixkaW1zLnVzZSkpCiMgYWxnb3JpdGhtPSA0IGlzIExlaWRlbiBhbGdvcml0aG0gLSBvZnRlbiBwZXJmb3JtcyBiZXR0ZXIKYGBgCgpQbG90IG9mIGEgY2x1c3RlcmluZyB0cmVlIHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNsdXN0ZXJpbmdzIGF0IGRpZmZlcmVudCByZXNvbHV0aW9ucy4gKHVzaW5nIHRoZSBjbHVzdHJlZSBwYWNrYWdlKQpgYGB7ciAsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4LHdhcm5pbmc9RkFMU0V9CmNsdXN0cmVlKHNldXIsIHByZWZpeCA9IHBhc3RlMCgiUk5BX3Nubl9QQyIsZGltcy51c2UsIl9yZXMuIikpICsKIGdndGl0bGUocGFzdGUoc3Vic2V0Lm5hbWUsIjogQ2x1c3RlcmluZyB0cmVlIFBDPSIsIGRpbXMudXNlKSkKYGBgCgpgYGB7ciAsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPTEwLHdhcm5pbmc9RkFMU0V9CnBsb3Q8LWxpc3QoKQpmb3IgKCByZXMgaW4gYygwLjUsIDAuNzUsMSwxLjI1KSkKcGxvdFtbYXMuY2hhcmFjdGVyKHJlcyldXTwtRGltUGxvdChzZXVyLCBwdC5zaXplID0gMSxsYWJlbD1ULHJlcGVsPVQsIGdyb3VwLmJ5ID0gcGFzdGUwKCJSTkFfc25uX1BDIixkaW1zLnVzZSwiX3Jlcy4iLHJlcykscmVkdWN0aW9uPXBhc3RlMCgidW1hcFBDIixkaW1zLnVzZSkpICsKICAgZ2d0aXRsZShwYXN0ZSgiUEMgPSIsZGltcy51c2UsInJlcz0iLHJlcykpCnBsb3RfZ3JpZChwbG90bGlzdD1wbG90KQpgYGAKClZpc3VhbGl6ZSB0aGUgc2FtZSBjbHVzdGVyaW5ncyBvbiBVTUFQIHdpdGggMTAgUEMKYGBge3IgLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0xMCx3YXJuaW5nPUZBTFNFfQpwbG90PC1saXN0KCkKZm9yICggcmVzIGluIGMoMC41LCAwLjc1LDEsMS4yNSkpCnBsb3RbW2FzLmNoYXJhY3RlcihyZXMpXV08LURpbVBsb3Qoc2V1cixsYWJlbD1ULHJlcGVsPVQsIGdyb3VwLmJ5ID0gcGFzdGUwKCJSTkFfc25uX1BDIixkaW1zLnVzZSwiX3Jlcy4iLHJlcyksICByZWR1Y3Rpb249ICBwYXN0ZTAoInVtYXBQQzEwIikpICsKICAgZ2d0aXRsZShwYXN0ZSgiUEMgPSIsZGltcy51c2UsInJlcz0iLHJlcykpCnBsb3RfZ3JpZChwbG90bGlzdD1wbG90KQpgYGAKCiMjIyBMZXQncyBmaW5kIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBwZXIgY2x1c3RlcgoKYGBge3Isd2FybmluZz1GQUxTRX0KcmVzPTEKSWRlbnRzKHNldXIpPSAgcGFzdGUwKCJSTkFfc25uX1BDIixkaW1zLnVzZSwiX3Jlcy4iLHJlcykKYGBgCmBgYHtyLHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CkRFZ2VuZXNfbGlzdDwtbGlzdCgpCmZvciAoIGkgaW4gbGV2ZWxzKElkZW50cyhzZXVyKSkpewpERWdlbmVzX2xpc3RbW2ldXTwtICBmaW5kLm1hcmtlcnMuZGV0YWlsZWQoc2V1cixpZGVudC4xLnVzZT1pLCBkYXRhc2V0Lm5hbWU9cGFzdGUoc2FtcGxlLm5hbWVzLCBzdWJzZXQubmFtZSksbWluLmNlbGxzLmdyb3VwLnVzZT0yLCBwc2V1ZG9jb3VudCA9IDAuMSkKfQpzYXZlUkRTKERFZ2VuZXNfbGlzdCwgcGFzdGUwKCBwYXRoLCJERWdlbmVzLnJlcyIscmVzLCJfIiwiUEMiLGRpbXMudXNlLCJfIixzdWJzZXQubmFtZSwiXyIsc2FtcGxlLm5hbWVzLCIucmRzIikpCmBgYAoKYGBge3Isd2FybmluZz1GQUxTRX0KcmVzPTEKZGltcy51c2U9MTAKREVnZW5lc19saXN0IDwtIHJlYWRSRFMoIHBhc3RlMCggcGF0aCwiREVnZW5lcy5yZXMiLHJlcywiXyIsIlBDIixkaW1zLnVzZSwiXyIsc3Vic2V0Lm5hbWUsIl8iLHNhbXBsZS5uYW1lcywiLnJkcyIpKQpgYGAKCmBgYHtyICwgZmlnLmhlaWdodCA9NywgZmlnLndpZHRoID0xMCx3YXJuaW5nPUZBTFNFfQpmZWF0dXJlcy51c2U9dW5saXN0KGxhcHBseShERWdlbmVzX2xpc3QsIGZ1bmN0aW9uKHgpIHsgaGVhZCh4W3gkYXZnX2xvZ0ZDPjAsXSRnZW5lKX0pKQpEb0hlYXRtYXAoc2V1ciwgZmVhdHVyZXMgPSBmZWF0dXJlcy51c2UsIGFzc2F5ID0gIlJOQSIsIGFuZ2xlID0gOTAsIGxhYmVsID1ULCBzaXplPTQpICsKICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsaGlnaCA9ICJyZWQiKSsKICB0aGVtZShheGlzLnRleHQueT0gZWxlbWVudF90ZXh0KHNpemU9MTApKSsKICBnZ3RpdGxlKHBhc3RlKCIgcmVzPSIscmVzLCAiIFBDPSAiLCBkaW1zLnVzZSkpCmBgYAoKCmBgYHtyLHdhcm5pbmc9RkFMU0V9CiMjIyBTYXZlIGFzIGV4Y2VsIHRhYmxlCnNldHdkKHBhdGgpCmZpcnN0X3NoZWV0X25hbWU8LW5hbWVzKERFZ2VuZXNfbGlzdClbMV0KI0pBVkEgc3BlY2lmaWMgZ2FyYmFnZSBjb2xsZWN0aW9uIApqZ2MgPC0gZnVuY3Rpb24oKSB7CiAgckphdmE6Oi5qY2FsbCgiamF2YS9sYW5nL1N5c3RlbSIsIG1ldGhvZCA9ICJnYyIpCiB9IAojQ3JlYXRlIHRoZSBleGNlbCBmaWxlIGFuZCBhZGQgdGhlIGZpcnN0IHNoZWV0CndyaXRlLnhsc3gyKERFZ2VuZXNfbGlzdFtbZmlyc3Rfc2hlZXRfbmFtZV1dLCBmaWxlPXBhc3RlMCgiREVnZW5lcy5yZXMiLHJlcywiXyIsIlBDIixkaW1zLnVzZSwiXyIsc3Vic2V0Lm5hbWUsIl8iLHNhbXBsZS5uYW1lcywiLnhsc3giKSwgc2hlZXROYW1lPWZpcnN0X3NoZWV0X25hbWUsIHJvdy5uYW1lcz1GQUxTRSkKI0FkZCB0aGUgcmVtYWluaW5nIHNoZWV0cyB0b3QgaGUgZXhjZWwgZmlsZQpmb3IgKCBpIGluIG5hbWVzKERFZ2VuZXNfbGlzdClbbmFtZXMoREVnZW5lc19saXN0KSE9Zmlyc3Rfc2hlZXRfbmFtZV0pIHsKICBnYygpCiAgamdjKCkKICBtZXNzYWdlKCJBZGRpbmcgc2hlZXQgIiwgaSkKICB3cml0ZS54bHN4MihERWdlbmVzX2xpc3RbW2ldXSwgZmlsZT1wYXN0ZTAoIkRFZ2VuZXMucmVzIixyZXMsIl8iLCJQQyIsZGltcy51c2UsIl8iLHN1YnNldC5uYW1lLCJfIixzYW1wbGUubmFtZXMsIi54bHN4IiksIHNoZWV0TmFtZT1pLCBhcHBlbmQ9VFJVRSwgcm93Lm5hbWVzPUZBTFNFKQp9CmBgYAoKCmBgYHtyfQpzYXZlUkRTKHNldXIscGFzdGUwKHBhdGgsc3Vic2V0Lm5hbWUsc2FtcGxlLm5hbWVzLCIuc2V1cmF0LnJkcyIpKQpgYGAKYGBge3J9CnNldXI8LXJlYWRSRFMocGFzdGUwKHBhdGgsc3Vic2V0Lm5hbWUsc2FtcGxlLm5hbWVzLCIuc2V1cmF0LnJkcyIpKQpgYGAKCgoKYGBge3Isd2FybmluZz1GQUxTRX0Kc2Vzc2lvbkluZm8oKQpgYGAKCgoKCgo=